using System;
using System.Windows.Forms;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.Demos;
using DevExpress.ExpressApp.Win.Core;
using DevExpress.ExpressApp.Xpo;
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using DevExpress.Xpo.DB.Helpers;

namespace FeatureCenter.Module.Win {
    public class SessionEventArgs : EventArgs {
        private UnitOfWork session;
        public SessionEventArgs(UnitOfWork session) {
            this.session = session;
        }
        public UnitOfWork Session {
            get { return session; }
        }
    }

    public class ObjectIndexEventArgs : EventArgs {
        private int index = 0;
        public int Index {
            get { return index; }
            set { index = value; }
        }
    }

    public class ObjectPoolCreationOptionsEventArgs : EventArgs {
        private int demoObjectsCount;
        private int demoObjectsCommitInterval;
        public ObjectPoolCreationOptionsEventArgs(int demoObjectsCount, int demoObjectsCommitInterval) {
            this.demoObjectsCount = demoObjectsCount;
            this.demoObjectsCommitInterval = demoObjectsCommitInterval;
        }
        public int DemoObjectsCount {
            get { return demoObjectsCount; }
            set { demoObjectsCount = value; }
        }
        public int DemoObjectsCommitInterval {
            get { return demoObjectsCommitInterval; }
            set { demoObjectsCommitInterval = value; }
        }
    }

    public class CreateDemoObjectsPoolController : LongOperationController {
        private const int defaultDemoObjectsCount = 2000;
        private const int defaultDemoObjectsCommitInterval = 50;
        private SimpleAction createDemoObjectsPoolAction;
        protected const string progressCaption = "Demo objects pool is being created...";
        protected const string progressMessageTemplate = "{0} objects are created of the {1} objects.";

        private UnitOfWork CreateUpdatingSession() {
            UnitOfWork session = new UnitOfWork(((XPObjectSpace)ObjectSpace).Session.DataLayer);
            OnUpdatingSessionCreated(session);
            return session;
        }
        private void CommitUpdatingSession(UnitOfWork session) {
            session.CommitChanges();
            OnUpdatingSessionCommitted(session);
        }
        private int GetInitialIndex() {
            if(GetInitialObjectIndex != null) {
                ObjectIndexEventArgs args = new ObjectIndexEventArgs();
                GetInitialObjectIndex(this, args);
                return args.Index;
            }
            return 0;
        }
        private void UpdateActionState(bool inProgress) {
            createDemoObjectsPoolAction.Enabled.SetItemValue("Creating objects", !inProgress);
        }
        private void CreateDemoObjectsPoolAction_Execute(object sender, SimpleActionExecuteEventArgs e) {
            StartLongOperation();
        }

        protected virtual void OnUpdatingSessionCommitted(UnitOfWork session) {
            if(UpdatingSessionCommitted != null) {
                UpdatingSessionCommitted(this, new SessionEventArgs(session));
            }
        }
        protected virtual void OnUpdatingSessionCreated(UnitOfWork session) {
            if(UpdatingSessionCreated != null) {
                UpdatingSessionCreated(this, new SessionEventArgs(session));
            }
        }
        protected override IProgressControl CreateProgressControl() {
            return new ProgressForm(progressCaption, 0, 100);
        }
        protected override void DoWorkCore(LongOperation longOperation) {
            int initialIndex = GetInitialIndex();
            UnitOfWork session = CreateUpdatingSession();

            ObjectPoolCreationOptionsEventArgs args = new ObjectPoolCreationOptionsEventArgs(defaultDemoObjectsCount, defaultDemoObjectsCommitInterval);
            BatchCreationOptionsAttribute creationOptionsAttribute = ((DevExpress.ExpressApp.ListView)View).ObjectTypeInfo.FindAttribute<BatchCreationOptionsAttribute>();
            if(creationOptionsAttribute != null) {
                if(creationOptionsAttribute.ObjectsCount.HasValue) {
                    args.DemoObjectsCount = creationOptionsAttribute.ObjectsCount.Value;
                }
                if(creationOptionsAttribute.CommitInterval.HasValue) {
                    args.DemoObjectsCommitInterval = creationOptionsAttribute.CommitInterval.Value;
                }
            }
            if(CustomizeObjectPoolCreationOptions != null) {
                CustomizeObjectPoolCreationOptions(this, args);
            }
            try {
                Type objectType = ((DevExpress.ExpressApp.ListView)View).ObjectTypeInfo.Type;
                for(int index = 0; index < args.DemoObjectsCount; index++) {
                    try {
                        if(index % args.DemoObjectsCommitInterval == 0) {
                            CommitUpdatingSession(session);
                            session.Dispose();
                            session = CreateUpdatingSession();
                        }

                        IObjectPropertiesInitializer newObject = ReflectionHelper.CreateObject(objectType, session) as IObjectPropertiesInitializer;
                        newObject.InitializeObject(index + initialIndex);

                        if(longOperation.Status == LongOperationStatus.InProgress) {
                            longOperation.RaiseProgressChanged((int)((index * 100) / args.DemoObjectsCount), string.Format(progressMessageTemplate, index + 1, args.DemoObjectsCount));
                        }
                        if(longOperation.Status == LongOperationStatus.Cancelling) {
                            return;
                        }
                    }
                    catch(LongOperationTerminateException) {
                        longOperation.CancelAsync();
                        break;
                    }
                }
            }
            finally {
                CommitUpdatingSession(session);
                session.Dispose();
            }
        }
        protected override void OnOperationStarted() {
            UpdateActionState(true);
            base.OnOperationStarted();
        }
        protected override void OnOperationCompleted() {
            UpdateActionState(false);
            base.OnOperationCompleted();
        }
        protected override void OnActivated() {
            base.OnActivated();
            Application.ViewShown += new EventHandler<ViewShownEventArgs>(Application_ViewShown);
        }
		protected override void OnDeactivated() {
			base.OnDeactivated();
            Application.ViewShown -= new EventHandler<ViewShownEventArgs>(Application_ViewShown);
        }
        protected void Application_ViewShown(object sender, ViewShownEventArgs e) {
            if(!Application.ConnectionString.Contains("XpoProvider")) {
                return;
            }

            ConnectionStringParser parser = new ConnectionStringParser(Application.ConnectionString);
            string provider = parser.GetPartByName("XpoProvider");

            if(provider == "XmlDataSet") {
                ShowPerformanceWarning();
            }
        }
        protected void ShowPerformanceWarning() {
            Messaging.DefaultMessaging.Show(Hints.PerformanceWarningText, "Performance warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
        public CreateDemoObjectsPoolController() {
            this.TargetObjectType = typeof(IObjectPropertiesInitializer);
            this.TargetViewType = ViewType.ListView;
            string actionID = string.Format("{0}.CreateDemoObjectsPool", this.GetType().Name);
            this.createDemoObjectsPoolAction = new SimpleAction(this, actionID, PredefinedCategory.Edit);
            this.createDemoObjectsPoolAction.Caption = "Create Demo Objects";
            this.createDemoObjectsPoolAction.Execute += new SimpleActionExecuteEventHandler(CreateDemoObjectsPoolAction_Execute);
            this.createDemoObjectsPoolAction.ConfirmationMessage = "You are about to generate a lot of objects. Do you want to continue?";
            UpdateActionState(false);
        }
        public string ActionCaption {
            get { return createDemoObjectsPoolAction.Caption; }
            set { createDemoObjectsPoolAction.Caption = value; }
        }
        public event EventHandler<SessionEventArgs> UpdatingSessionCreated;
        public event EventHandler<SessionEventArgs> UpdatingSessionCommitted;
        public event EventHandler<ObjectIndexEventArgs> GetInitialObjectIndex;
        public event EventHandler<ObjectPoolCreationOptionsEventArgs> CustomizeObjectPoolCreationOptions;
    }
}
